// Proxy es6 构造函数
// defineProperty 劫持数据  给对象进行扩展   属性进行设置


// target 目标对象，要进行处理的对象
// handler 容器   无数可以处理对象属性的方法
// 自定义对象属性的获取，赋值 枚举 函数调用的等功能
// var proxy = new Proxy(target, handler)

var target = {
    a: 1,
    b: 2
}
let proxy = new Proxy(target, {
        get(target, prop) {
            console.log(prop);
            console.log('this');
        },
        set(target, prop, value) {
            target[prop] = value;
            console.log(target[prop]);
        }
    })
    //代理对象才会走代理方法，源对象不会走
console.log(target.a); //1
console.log(proxy.a); //this
proxy.a = 09;
target.a = 1
console.log(proxy);
console.log(target);
console.log('-------------------分割线---------------------');
let arr = [{
        name: '小明',
        age: 12
    },
    {
        name: '小黄',
        age: 52
    },
    {
        name: '小红',
        age: 72
    },
    {
        name: '小绿',
        age: 32
    },
    {
        name: '小蓝',
        age: 42
    },
    {
        name: '小白',
        age: 32
    },
    {
        name: '小黑',
        age: 112
    },
]
let persons = new Proxy(arr, {
    get(arr, prop) {
        return arr[prop]
    },
    set(arr, prop, value) {
        arr[prop] = value
    }
})
console.log(persons[3]);
persons[1] = {
    name: '小小黑',
    age: 112
}
console.log(persons);
console.log('-------------------分割线---------------------');

let fn = function() {
    console.log('function');
}
fn.a = 123;
let newFn = new Proxy(fn, {
    get(fn, prop) {
        return 'function'
    }
})
console.log(newFn.a);
console.log('-------------------分割线---------------------');
// 对象操作的 14种方法
var obj = {
        a: 1,
        b: 2
    }
    //1. 获取原型 [[GetPrototypeOf]]
    // var proto = Object.getPrototypeOf(obj);
    // console.log(proto);
    // console.log(obj.__proto__);
    // console.log(Object.prototype);
    // js很多命令都是通过关键字获得的。方法式

// 2. 设置原型 [[SetPrototypeOf]]
// Object.setPrototypeOf(obj, { c: 23, d: 4 })
// console.log(obj);

// 3.获取对象的可扩展性 [[IsExtensible]]
// var extensible = Object.isExtensible(obj);
// console.log(extensible);

// Object.freeze(obj); //冻结 不可写 不可修改 不可删除
// var extensible1 = Object.isExtensible(obj);
// console.log(extensible1);


// Object.seal(obj); //封闭对象，不可修改,不可删除，不可写
// obj.c = 3;
// obj.b = 32
// console.log(obj); //{a: 1, b: 32}

//4. 获取自由属性 [[GetOwnProperty]]
// 自由属性是存在于对象上的属性，并不是存在原型链上的属性
// Object.setPrototypeOf(obj, { c: 23, d: 4 })
// console.log(Object.getOwnPropertyNames(obj));

// 5.禁止扩展对象 [[PreventExtensions]]
// Object.preventExtensions(obj);
// obj.c = 3; //禁止增加属性
// delete obj.a //可删除
// console.log(obj)

// 6.拦截对象操作  [[DefineOwnProperty]]
// Object.defineProperty()

// 7.判断是否是自身属性 [[HasProperty]]
// console.log(obj.hasOwnProperty('a'));

// 8.[[GET]]
// 都是通过get方法实现的
// console.log(obj.a);

// 9 [[SET]]
// obj.a = 8790;
// console.log(obj);

// 10.[[Delete]]
// delete obj.a;
// console.log(obj);
// 11.[[Enumerate]]

// for (var k in obj) {
//     console.log(obj[k]);
// }

// 12. 获取键集合[[OwnPropertyKeys]]
// console.log(Object.keys(obj));

// 13. 调用函数
// function test() {
//     console.log('function');
// };
// test()
// 14.new
console.log('-------------------分割线---------------------');

function MyProxy(target, handler) {
    let _target = deepClone(target);
    Object.keys(_target).forEach(key => {
        Object.defineProperty(_target, key, {
            get() {
                return handler.get && handler.get(target, key);
            },
            set(newVal) {
                handler.set && handler.set(target, key, newVal)
            }
        })
    });
    return _target;
    //深拷贝
    function deepClone(org, tar) {
        var tar = tar || {},
            toStr = Object.prototype.toString,
            arrType = '[object Array]';
        for (var key in org) {
            if (org.hasOwnProperty(key)) {
                if (typeof(org[key]) === 'object' && org[key] !== null) {
                    tar[key] = toStr.call(org[key]) === arrType ? [] : {};
                    deepClone(org[key], tar[key])
                } else {
                    tar[key] = org[key]
                }
            }
        }
        return tar
    }
}
let target1 = {
    a: 1,
    b: 2
}
let proxy1 = new MyProxy(target1, {
    get(target, prop) {
        return 'GET:' + prop + '=' + target[prop]
    },
    set(target, prop, value) {
        target[prop] = value;
        console.log('SET:' + prop + '=' + value);
    }
})
console.log(proxy1.a);
proxy1.a = 123
console.log('-------------------分割线---------------------');
//重写Proxy中的方法
var proxy2 = new Proxy(target1, {
    get(target, prop) {
        // return 'GET:' + prop + '=' + target[prop]
        //Reflect 反射， 方法容器
        return Reflect.get(target, prop);
    },
    set(target, prop, value) {
        target[prop] = value;
        console.log('SET:' + prop + '=' + value);
    },
    has(target, prop) {
        console.log(target[prop]);
    }
})
console.log('a' in proxy2);
console.log(proxy2.a);
// 数组的push等方法是无法触发defineProperty种的set方法

//Reflect
//现在很多方法都放在Object中，但是Object只是构造方法。这样就不太合理，于是出现Reflect
// Reflect内部方法集合的容器 内置全局容器，保存静态方法